<?php /* 
==================================================
TextCMS -- simple plain/text CMS with GPL licence
Admincenter file manager module
(c) 2008, 4X_Pro
Visit us online: http://textcms.ru
==================================================

TODO: 
+ сделать копирование/перенос файлов
& добавить сортировку файлов  -- частично сделано
* добавить прокрутку таблицы с файлами и подогнать размеры для 1024x768
+ добавить вывод сообщения о том, сколько файлов удалено/скопировано/переименовано 
* добавить возможность догрузки части файла при просмотре текстовых файлов
+ добавить параметр dir в форму переименования/подтверждения файлов 
* добавить вывод картинок с типом файла
* сделать пиктограммы для кнопок действий
+ макс размер файла для загрузки
+ показ предпросмотра больших файлов по ссылке при выключенном JavaScript
+ сделать транслитерацию имен файлов в отдельной процедуре и применять ее ко всему
*/

function fileman_view() {
  $basedir = cms_basedir();
  $dir = _fileman_getdir();
  if (!cms_ajax()) { // если запрос -- не AJAX, то выставляем настройки кнопок
    $page = cms_output_load_template('fileman.htm','fileman');
    $page = str_replace('#dir#',$_REQUEST['dir'],$page);
    if (ini_get('file_uploads')) {
      $maxsize = min(_fileman_bytes(ini_get('upload_max_filesize')),
        _fileman_bytes(ini_get('post_max_size')),_fileman_bytes(ini_get('memory_limit')));
      $uploadmsg=round($maxsize/1024).' Кб';
    }
    else $uploadmsg='ЗАГРУЗКА ФАЙЛОВ ОТКЛЮЧЕНА!';
    $page=str_replace('#upload#',$uploadmsg,$page);
    if (!isset($_SESSION['fileman']['buffer']) || !isset($_SESSION['fileman']['buffer_dir'])) 
      $buffermsg='" disabled="disabled" title="Буфер обмена пуст!'; // Кавычки расставлены столь странным образом, так как #buffer# находится внутри конструкции name="paste#buffer#" 
    else $buffermsg='" title="В буфере '.count($_SESSION['fileman']['buffer']).' файл(ов) из каталога '.htmlspecialchars(str_replace($basedir,'',$_SESSION['fileman']['buffer_dir'])); //
    $page = str_replace('#buffer#',$buffermsg,$page);
  }
  cms_jscript('jquery.js','jquery.ocupload.js','jquery.form.js');
  $warn=false;
  if (strpos($dir,$basedir.'upload/')!==0 && $dir!=$basedir.'upload') {
    $message='Внимание! Совершение операций над файлами данных TextCMS вне каталога upload может привести к утере информации сайта! Будьте уверены в том, что вы знаете, что вы делаете!';
    $warn=true;
  }
  else $message='';
  
  if (!cms_valid_file($dir)) {
    $message = 'Имя каталога содержит недопустимые символы!';
  }
  elseif (!is_dir($dir)) {
    $message = 'Такого каталога не существует!';
  }
  else {
    cms_module_load('cmsmain',true);
    if (!cms_ajax() || !isset($_REQUEST['file'])) {
      $_SESSION['fileman']['dir']=$_REQUEST['dir'];
      $dh = opendir($dir);
      $files = array();
      while ($curfile=readdir($dh)) {
        if ($curfile!='.' && ($dir!=$basedir || $curfile!='..')) {
          $tmp=stat($dir.'/'.$curfile);
          if (!cms_ajax() && !isset($_REQUEST['file'])) $_REQUEST['file']=(isset($_SESSION['fileman']) && isset($_SESSION['fileman']['file'])) ? $_SESSION['fileman']['file'] : $curfile;          
          $fdata['name']=$curfile;
          $fdata['short']=strlen($fdata['name']<32) ? $fdata['name'] : substr($fdata['name'],0,32).'...';
          $fdata['dblclick']='';
          if ($tmp[2] & 040000) {
            $fdata['short']='<b>'.$fdata['short'].'</b>';
            $dirlink = _fileman_getsubdir($curfile);
            $fdata['size']='<b><a href="'.$dirlink.'">DIR</a></b>';
            $fdata['dblclick']='ondblclick="document.location.href=\''.$dirlink.'\'" ';
          }
          else $fdata['size']=_fileman_size($tmp[7]);
          
          $fdata['filesize']=$tmp[7];
          $fdata['attr']=$tmp[2];
          $fdata['mode']=decoct($tmp[2]);
          $fdata['lastmod']=strftime('%d.%m.%Y %H:%M',$tmp[9]);
          $fdata['lastmodtime']=$tmp[9];
          $fdata['link']=$_SERVER['PHP_SELF'].'?a=fileman_view&amp;file='.$curfile.'#';
          
          $files[]=$fdata;
        }
      }
      closedir($dh);

// сортировка файлов      
      if (isset($_REQUEST['sort'])) $_SESSION['fileman']['sort']=$_REQUEST['sort'];
      elseif (!isset($_SESSION['fileman']['sort'])) $_SESSION['fileman']['sort']='name';
      if (isset($_REQUEST['desc'])) $_SESSION['fileman']['desc']=$_REQUEST['desc'];
      elseif (!isset($_SESSION['fileman']['desc'])) $_SESSION['fileman']['desc']='';
      usort($files,create_function('$a,$b','
        $coeff=($_SESSION["fileman"]["desc"]) ? -1 : 1;
        if ((($a["attr"] & 040000) && ($b["attr"] & 040000)==0) || $a["name"]=="..") return -1;
        elseif ((($a["attr"] & 040000)==0 && ($b["attr"] & 040000)) || $b["name"]=="..") return 1;
        elseif ($_SESSION["fileman"]["sort"]=="date") return $coeff*($a["lastmodtime"]-$b["lastmodtime"]);
        elseif ($_SESSION["fileman"]["sort"]=="size") return $coeff*($a["filesize"]-$b["filesize"]);
        else return $coeff*strcmp($a["name"],$b["name"]); '));
        
      $fileentry = cms_output_load_template('entry.htm','fileman');
      $filelist = '';
      for ($i=0, $count=count($files); $i<$count; $i++) {
        $buffer=cmsmain_replace($fileentry,$files[$i]);
        if (isset($_REQUEST['file']) && $files[$i]['name']==$_REQUEST['file']) $buffer=str_replace('<tr>','<tr class="active">',$buffer);
        $filelist.=$buffer;
      }
      if (!$filelist) return 'Файлы в текущем каталоге отсутствуют!';
      else {
        $fileresult = cms_output_load_template('files.htm','fileman');
        $fileresult = str_replace('#FILES#',$filelist,$fileresult);
      }
      if (cms_ajax()) return $fileresult;
      if (!$message && !is_writable($dir)) { $message='Каталог недоступен для записи! Некоторые операции будут невозможны.'; $warn=1; }
    }
    if (isset($_REQUEST['file'])) {
      $fileinfo = cms_output_load_template('info.htm','fileman');
      $filename=$dir.'/'.$_REQUEST['file'];
//      $fileinfo = cmsmain_replace($fileinfo,$fdata);
      if (!cms_valid_file($filename) && $filename!=$dir.'/..') {
        $message = 'Неправильное имя файла!';
      }
      elseif (!file_exists($filename)) {
        $message = 'Файла '.htmlspecialchars($filename).' не существует!';
      }
      else {
        $_SESSION['fileman']['file']=$_REQUEST['file'];        
        $tmp=stat($filename);
        $fdata['name']=$_REQUEST['file'];
        $fdata['url']=((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']!='off') ? 'https://' : 'http://').$_SERVER['HTTP_HOST'];
        if ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']!='off') && $_SERVER['SERVER_PORT']!=443) $fdata['url'].=':'.$_SERVER['SERVER_PORT'];
        elseif ($_SERVER['SERVER_PORT']!=80) $fdata['url'].=':'.$_SERVER['SERVER_PORT'];
        if ($tmp[2] & 040000) {
          $fdata['infomsg']='Перейти в каталог';
          $fdata['url']=_fileman_getsubdir($fdata['name']);
          $fdata['urllink']='';
        }
        else {
          $fdata['infomsg']='Скачать файл (полная ссылка)';        
          $fdata['url'].=$GLOBALS['sitepath'].$dir.'/'.$_REQUEST['file'];
          $fdata['urllink']='Отн.&nbsp;адрес: \##url['.$dir.'/'.$_REQUEST['file'].']#<br />';
        }
        $fdata['size']=_fileman_size($tmp[7]).' ('.$tmp[7].' байт)';
        $fdata['mode']=decoct($tmp[2]);
        $fdata['lastmod']=strftime('%d %B %Y, %H:%M',$tmp[9]);
        if (function_exists('posix_getpwuid')) {
          $uid=posix_getpwuid($tmp[4]);
          $fdata['owner']=($uid['name']).' ('.$tmp[4].')';
        }
        else $fdata['owner']='Не доступно'; 
        if (function_exists('posix_getgrgid')) {
          $fdata['group']=($gid['name']).' ('.$tmp[5].')';
          $gid=posix_getgrgid($tmp[5]);
        }
        else $fdata['group']='Не доступно';
        
        if (preg_match('/\.(jpe?g|gif|bmp|png)$/i',$filename)) {
          if ($tmp[7]<100*1024 || isset($_GET['preview'])) {
            $fdata['preview']='<img src="'.$fdata['url'].'" style="width:100%" alt="Предварительный просмотр" />';
          }
          else { // \'<img src=\\"'.$fdata['url'].'\\" style=\\"width:100%\\" alt=\\"Предварительный просмотр\\" /\'+\'>\'"
            $fdata['preview']='<div style="font-size: 150%; text-align: center">Файл имеет достаточно большой размер! При просмотре он будет загружен полностью.<br /> '.
            '<a href="admin.php?a=fileman_view&amp;file='.$_REQUEST['file'].'&amp;preview=1" onclick="this.parentNode.innerHTML=\'<img src=\\\''.$fdata['url'].'\\\' style=\\\'width:100%\\\' alt=\\\'Предварительный просмотр\\\'/\'+\'>\'; return false;">Посмотреть все равно</a>.</div>';
          }
        }
        elseif (preg_match('/\.(txt|cfg|conf|ini|php\d?|inc|pl|html?|c|cpp|pas|sh|py)$/i',$filename)) {
          $fdata['preview']='';
          if (!is_readable($filename)) $fdata['preview']='<div class="errmsg">Файл недоступен для чтения!</div>';
          else {
            $fh=fopen($filename,'r');
            $fdata['preview']='<pre>';
            for ($i=0; $i<15; $i++) {
              $buffer=fgets($fh);
              if (strlen($buffer>80)) $buffer=substr($buffer,0,80)."...\n";
              $fdata['preview'].=htmlspecialchars($buffer);
            }
            $fdata['preview'].='</pre>';
            fclose($fh);
          }
        }
        else {
          $fdata['preview']='<div class="warnmsg">Предпросмотр данного типа файлов не поддерживается!</div>';
        }
        $fileinfo=cmsmain_replace($fileinfo,$fdata);
        if (cms_ajax()) return $fileinfo;
      }
    }
    else $fileinfo='';
    $page = str_replace('#FILELIST#',$fileresult,$page);
    $page = str_replace('#FILEINFO#',$fileinfo,$page);
  }
  if ($message && cms_ajax()) { 
    return '<div class="errmsg">'.$message.'</div>';
  }
  elseif ($message && !$warn) $message='<div class="errmsg">'.$message.'</div>';
  elseif ($message && $warn) $message='<div class="warnmsg">'.$message.'</div>'; 
  if (isset($_SESSION['fileman']['status'])) {
    $message=$_SESSION['fileman']['status'].$message;
    unset($_SESSION['fileman']['status']);
  }
  $page = str_replace('#message#',$message,$page);
    
  return $page;
}

function fileman_delete() {
  $files = _fileman_getfiles();

  if ((!isset($_REQUEST['confirm']) || !$_REQUEST['confirm']) && cms_module_load('admstart')) {
    return admstart_confirm('Вы действительно хотите удалить эти файлы: <br />'.join(', ',$files),'admin.php?a=fileman_view');
  }
  else {
    $dir = _fileman_getdir();
    if (!is_writable($dir)) $message='<div class="errmsg">Каталог защищен от записи! Удаление файлов невозможно.</div>';
    else {
      $deleted=0;
      $errors=0;
      for ($i=0, $count=count($files); $i<$count; $i++) {
        if (_fileman_delete($dir.'/'.$files[$i])) {
          $deleted++;
          if ($_SESSION['fileman']['file']==$files[$i]) unset($_SESSION['fileman']['file']);
        }
        else $errors++;
      }
      if ($errors==0) $message ='<div class="okmsg">Файлов удалено: '.$deleted.'.</div>';
      else $message ='<div class="warnmsg">Файлов удалено: '.$deleted.', ошибок при удалении: '.$errors.'.</div>';
      
      if (cms_ajax()) return $message;
      else {
        $_SESSION['fileman']['status']=$message;
        $GLOBALS['status']=302;
        $GLOBALS['location']='admin.php?a=fileman_view';
      }
    }
  }
}

/** Редактирование файла **/
function fileman_edit() {
  if (isset($_POST['return'])) {
    $GLOBALS['status']=302;
    $GLOBALS['location']='admin.php?a=fileman_view';
    return;
  }
  $dir = _fileman_getdir();
  $message='';
  $status=false;
  if (isset($_POST['save']) || isset($_POST['save_continue'])) { // сохраняем отредактированный файл
    $filename=$dir.'/'.$_POST['file'];
    if (!cms_valid_file($filename)) {
      $message='<div class="errmsg">Неправильное имя файла!</div>';
    }
    elseif (!is_writable($filename)) $message='Файл недоступен для записи!';
    else {
      $fh=fopen($filename,'w');
      flock($fh,LOCK_EX);
      fwrite($fh,$_POST['data']);
      fclose($fh);
      
      $message='<div class="okmsg">Файл '.$_POST['file'].' успешно сохранен!</div>';
      $_SESSION['fileman']['status']=$message;
      $_SESSION['fileman']['file']=$_POST['file'];
      if (isset($_POST['save'])) {
        $GLOBALS['status']=302;
        $GLOBALS['location']='admin.php?a=fileman_view';
        $status=true;
        return;
      }
      else return $message;
    }
  }
  if (!$status) {
    $page = cms_output_load_template('edit.htm','fileman');
    if (isset($_POST['file'])) $filename=$dir.'/'.$_POST['file'];
    else $filename=$dir.'/'.$_SESSION['fileman']['file'];
    $message=false;
    if (!cms_valid_file($filename)) $message='<div class="errmsg">Неправильное имя файла!</div>';
    elseif (!is_readable($filename)|| !is_file($filename)) $message='<div class="errmsg">Файл с указанным именем не существует, не является обычным файлом или недоступен для чтения!</div>';
    elseif (!is_writable($filename)) $message='<div class="warnmsg">Файл недоступен для записи!</div>';
    if (!$message) {
      if (isset($_POST['data'])) $buffer=$_POST['data'];
      else {
        $fh=fopen($filename,'r');
        flock($fh,LOCK_SH);
        $buffer='';
        while ($curbuf=fgets($fh)) $buffer.=$curbuf;
        fclose($fh);
      }
      $page=str_replace('#data#',htmlspecialchars($buffer),$page);
      $page=str_replace('#file#',htmlspecialchars(isset($_POST['file']) ? $_POST['file'] : $_SESSION['fileman']['file']),$page);
      $page=str_replace('#dir#',htmlspecialchars($_REQUEST['dir']),$page);
      $page=str_replace('#message#',$message,$page);
      return $page;      
    }
    else {
      if (!cms_ajax()) {
        $GLOBALS['status']=302;
        $GLOBALS['location']='admin.php?a=fileman_view';
        $_SESSION['fileman']['status']=$message;
      }
      else return $message;
    }
  }
}

/** Извлечение файлов из "буфера обмена". **/
function fileman_get() {
  $dir = _fileman_getdir();
  if (!isset($_SESSION['fileman']['buffer']) || !isset($_SESSION['fileman']['buffer_dir'])) $_SESSION['fileman']['status']='<div class="warnmsg">Буфер обмена пуст!</div>';
  elseif ($dir==$_SESSION['fileman']['buffer_dir']) $_SESSION['fileman']['status']='<div class="warnmsg">Копирование или перемещение файлов в тот же самый каталог, где они находятся, не имеет смысла.</div>';
  elseif (!cms_valid_file($_SESSION['fileman']['buffer_dir']) || !is_dir($_SESSION['fileman']['buffer_dir'])) $_SESSION['fileman']['status']='<div class="errmsg">Некорректно указан исходный каталог! Поместите файлы в буффер обмена еще раз!</div>';
  elseif (!cms_valid_file($dir)) $_SESSION['fileman']['status']='<div class="errmsg">Имя исходного каталога некорректно!</div>';
  elseif (!is_writeable($dir)) $_SESSION['fileman']['status']='<div class="errmsg">Текущий каталог недоступен для записи! Операция не может быть выполнена.</div>';
  else {
    $errors=0;
    $process=0;
    foreach ($_SESSION['fileman']['buffer'] as $curfile) {
      _fileman_copy($_SESSION['fileman']['buffer_dir'],$curfile,$dir) ? $process++ : $error++;
      if ($_SESSION['fileman']['mode']==2 && substr($dir,$_SESSION['fileman']['buffer_dir'].'/'.$curfile.'/')!==0) _fileman_delete($_SESSION['fileman']['buffer_dir'].'/'.$curfile);
    }
    $act=($_SESSION['fileman']['mode']==2) ? 'перемещено' : 'скопировано'; 
    $message='<div class="okmsg">Файлов '.$act.': '.$process.'.</div>';
    if ($errors!=0) $message='<div class="warnmsg">Файлов '.$act.': '.$process.'. Ошибок при переименовании: '.$errors.'.</div>';
    $_SESSION['fileman']['status']=$message;
    unset($_SESSION['fileman']['buffer']);
    unset($_SESSION['fileman']['buffer_dir']);    
  }
  if (!cms_ajax()) {
    $GLOBALS['status']=302;
    $GLOBALS['location']='admin.php?a=fileman_view';
  }
  return $_SESSION['fileman']['status'];
}

/** Создание подкаталога **/
function fileman_mkdir() {
  if (isset($_POST['return'])) {
    $GLOBALS['status']=302;
    $GLOBALS['location']='admin.php?a=fileman_view';
    return;
  }
  $dir = _fileman_getdir();
  $message='';
  if (isset($_POST['save'])) {
    $_POST['newdir']=_fileman_transliterate($_POST['newdir']);
    $dirname=trim($dir.'/'.$_POST['newdir']);
    if (!cms_valid_file($dirname)) $message='<div class="errmsg">Неправильное имя каталога!</div>';
    elseif (!is_writable($dir)) $message='<div class="errmsg">Текущий каталог недоступен для записи!</div>';
    else {
      if (!mkdir($dirname)) $message='<div class="errmsg">Не удалось создать каталог '.htmlspecialchars($_POST['newdir']).'</div>';
      else $message='<div class="okmsg">Каталог '.htmlspecialchars($_POST['newdir']).' создан!</div>';
    }      
    if (!cms_ajax()) {
      $_SESSION['fileman']['status']=$message;
      $GLOBALS['status']=302;
      $GLOBALS['location']='admin.php?a=fileman_view';
    }
    else return $message;
  }
  else {
    $page = cms_output_load_template('mkdir.htm','fileman');
    $page=str_replace('#dir#',htmlspecialchars($_REQUEST['dir']),$page);
    return $page;
  }
}

/** Все кнопки находятся в одной форме, поэтому требуется вспомогательная процедура, осуществляющая выбор и вызов**/
function fileman_process() {
  if (isset($_POST['edit'])) return fileman_edit();
  if (isset($_POST['mkdir'])) return fileman_mkdir();  
  if (isset($_POST['rename'])) return fileman_rename();
  if (isset($_POST['delete'])) return fileman_delete();
  if (isset($_POST['upload'])) return fileman_upload();
  if (isset($_POST['copy'])) return fileman_put(1);
  if (isset($_POST['cut'])) return fileman_put(2);
  if (isset($_POST['paste'])) return fileman_get();  
}

/** Процедура переименования выбранных файлов **/
function fileman_rename() {
  $dir = _fileman_getdir();  
  if (isset($_POST['do_rename'])) {
    $renamed=0;
    $errors=0;
    foreach ($_POST['files'] as $oldname=>$newname) {
      if (cms_valid_file($dir.'/'.$oldname)) { 
        $newname=_fileman_transliterate($newname);
        if (rename($dir.'/'.$oldname,$dir.'/'.$newname)) {
          $renamed++;
          if ($oldname==$_SESSION['fileman']['file']) $_SESSION['fileman']['file']=$newname;
        }
        else $errors++;
      }
      else $errors++;
    }
    $message='<div class="okmsg">Файлов переименовано: '.$renamed.'.</div>';
    if ($errors!=0) $message='<div class="warnmsg">Файлов переименовано: '.$renamed.'. Ошибок при переименовании: '.$errors.'.</div>';
    
    $_SESSION['fileman']['status']=$message;
    $GLOBALS['status']=302;
    $GLOBALS['location']='admin.php?a=fileman_view';
    return $message;
  }
  else {
    $files=_fileman_getfiles();
    $page = cms_output_load_template('rename.htm','fileman');
    $buffer = '';
    $entry = cms_output_load_template('renentry.htm','fileman');
    for ($i=0, $count=count($files); $i<$count; $i++) {
      $buffer.=str_replace('#name#',htmlspecialchars($files[$i]),$entry);
    }
    if ($count>0) $page = str_replace('#RENAME#',$buffer,$page);
    else $page = '<div class="errmsg">Нет файлов для переименования!</div>'; 
    return $page;
  }
}

/** Копирование файлов "в буфер обмена" (на самом деле происходит только 
запоминание имен файлов и каталога, где они находятся). **/
function fileman_put($mode=1) {
  $_SESSION['fileman']['buffer']=_fileman_getfiles();
  $_SESSION['fileman']['buffer_dir']=_fileman_getdir();
  $_SESSION['fileman']['mode']=$mode;
  $_SESSION['fileman']['status']='<div class="okmsg">'.count($_SESSION['fileman']['buffer']).' файлов помоещено в буфер.</div>';
  if (!cms_ajax()) {
    $GLOBALS['status']=302;
    $GLOBALS['location']='admin.php?a=fileman_view';
  }
}

/** Обработка загрузки файлов или вывод формы для такой загрузки 
(в случае, если не работает JavaScript, 
  при включенном JS загрузка выполняется прямо со страницы списка файлов) **/
function fileman_upload() {
  if (isset($_FILES['file'])) {
    if (is_uploaded_file($_FILES['file']['tmp_name'])) {
      $name = $_FILES['file']['name'];
      $name=_fileman_transliterate($name);
      $dir = _fileman_getdir();
      if (move_uploaded_file($_FILES['file']['tmp_name'],$dir.'/'.$name)) $status=1; 
      else $status=-100; 
    }
    else $status=$_FILES['file']['error'];

    if ($status==1) $statusmsg ='<div class="okmsg">Файл успешно загружен под именем '.htmlspecialchars($name).'!</div>';
    elseif ($status==-100) $statusmsg ='<div class="errmsg">При сохранении файла возникла ошибка! </div>'; 
    else $statusmsg ='<div class="errmsg">При попытке загрузки файла возникла ошибка '.$status.'</div>';
    
    $_SESSION['fileman']['status']=$statusmsg;
    if (!cms_ajax()) {
      $GLOBALS['status']=302;
      $GLOBALS['location']='admin.php?a=fileman_view';
    }
    else return $statusmsg;
  }
  else {
    $page = cms_output_load_template('upload.htm','fileman');
    return $page;
  }
}

function _fileman_bytes($val) {
  $val = trim($val);
  $last = strtolower($val{strlen($val)-1});
  switch($last) {
      // The 'G' modifier is available since PHP 5.1.0
      case 'g': $val *= 1024;
      case 'm': $val *= 1024;
      case 'k': $val *= 1024;
  }
  return $val;
}

/** Процедура рекурсивного удаления файлов и каталогов **/
function _fileman_delete($file) {
  if (!cms_valid_file($file)) return false;
  else {
    if (preg_match('#files/+site\d+/+(content\.txt|config\.php|content)$#',$file)) return false;
    if (is_dir($file)) { // если удаляем каталог, то удаляем рекурсивно и все его содержимое
      $dh=opendir($file); // обходим все файлы удаляемого каталога
      if (!$dh) return false;
      while ($curfile=readdir()) if ($curfile!='.' && $curfile!='..') _fileman_delete($file.'/'.$curfile); 
      closedir($dh);
      return rmdir($file);
    }
    else return unlink($file);
  }
}

/** Процедура рекурсивного копирования файлов и каталогов **/
function _fileman_copy($olddir,$oldfile,$newdir) {
  if (!cms_valid_file($oldfile)) return false;
  else {
    $oldfilename=$olddir.'/'.$oldfile; // старое имя файла
    $newname=$newdir.'/'.$oldfile; // новое имя файла
    if (!cms_valid_file($newname)) return false;
    if (is_dir($oldfilename)) { // если удаляем каталог, то копируем рекурсивно и все его содержимое
      if (mkdir($newname)) {
        $dh=opendir($oldfilename); // обходим все файлы удаляемого каталога
        if (!$dh) return false;
        while ($curfile=readdir()) if ($curfile!='.' && $curfile!='..') _fileman_copy($oldfilename,$curfile,$newname); 
        closedir($dh);
        return true;
      }
      else return false;
    }
    else return copy($oldfilename,$newname);
  }
}

/** Получение рабочего каталога для файл-менеджера **/
function _fileman_getdir() {
  $basedir = cms_basedir();  
  if (isset($_REQUEST['dir'])) { // если каталог явно указан в запросе, запоминаем его в сессию
    $_SESSION['fileman']['dir']=$_REQUEST['dir'];
    if (isset($_GET['dir'])) unset($_SESSION['fileman']['file']);
  } // иначе -- берем его из сессии, чтобы не таскать в параметрах
  else {
    $_REQUEST['dir'] = (isset($_SESSION['fileman']) && isset($_SESSION['fileman']['dir'])) ? $_SESSION['fileman']['dir'] : 'upload';
  }
  $dir = $basedir.$_REQUEST['dir'];  
  $dir = preg_replace('|/+|','/',$dir);
  if (!cms_valid_file($dir)) {
    unset($_SESSION['fileman']['dir']);
    return false;
  }
  return $dir;
}

/** Получение списка файлов, выбранных для проведения операции **/ 
function _fileman_getfiles() {
  if (isset($_POST['files']) && is_array($_POST['files'])) $files = array_keys($_POST['files']);
  else $files=array($_SESSION['fileman']['file']);
  return $files;
}

function _fileman_getsubdir($curfile) {
  $basedir = cms_basedir();
  $dir = $_REQUEST['dir'];
  if ($curfile=='..') {
    $parent_dir=str_replace($basedir,'',$dir);
    $parent_dir=(($pos=strrpos($parent_dir,'/'))===false) ? '/' : substr($parent_dir,0,$pos);
    $dirlink=$_SERVER['PHP_SELF'].'?a=fileman_view&amp;dir='.$parent_dir;
  }
  else $dirlink=$_SERVER['PHP_SELF'].'?a=fileman_view&amp;dir='.($_REQUEST['dir']=='/' ? '/' : $_REQUEST['dir'].'/').$curfile;
  return $dirlink;
}

function _fileman_size($size) {
  if ($size<100*1024) {
    $result=sprintf('%d&nbsp;Кб',round($size/1024));        
  }
  elseif ($size<100*1024*1024) {
    $result=sprintf('%.1f&nbsp;Мб',round($size*10/(1024*1024))/10);
  }
  else {
    $result=sprintf('%.1f&nbsp;Гб',round($size*10/(1024*1024*1024))/10);
  }
  return $result;
}

/** Транслитерация имен файлов, а также удаление из них потенциально опасных символов. **/ 
function _fileman_transliterate($name) {
  if (!isset($GLOBALS['config']['filetrans']) || $GLOBALS['config']['filetrans']==1) {
    if (cms_module_load('cmsmain')) {
      $name = cmsmain_transliterate($name);
    }
    $name = str_replace(' ','_',$name);
  }
  $name=str_replace(array('`','~','\'','"',';'),'_',$name);
  return $name;
}
